"""

Adder Bytecode Executor

"""

import sys
import types

class Obj(object):
	def __init__(self, type):
		self.type = type
		self.variables = dict()
		self.functions = dict()
		self.events = dict()
		self.constructor = None
	
	def clone(self):
		# This function is used when a new instance of the class is created.
		c = Obj(self.type);
		c.variables = self.variables.copy()
		c.functions = self.functions.copy()
		c.events = self.events.copy()
		if (self.constructor != None):
			c.constructor = self.constructor
		else:
			c.constructor = None
		return c

class Func(object):
	def __init__(self, name, args):
		self.name = name
		self.args = args
		self.code = ""
	
	def execute(self, engine, args):
		# Execute function here.
		a = 0
		for i in self.args:
			engine.variables[i] = args[a]
			a += 1
		
		engine.runByteCode(self.code.split("\n"))

# Now import Builtins
import Builtins
import ExceptionBIC

class Bite():
	def __init__(self):
		self.register = dict()
		self.variables = dict()
		self.classes = dict()
		self.functions = dict()
		self.bytecode_labels = dict()
		self.imports = list()
		
		self.return_scope = None
		
		self.debug = False
		self.filename = "<string>"
		self.current_line = 0
		self.current_interpreted_line_string = None
		self.current_interpreted_line_number = None
		self.current_interpreted_line_filename = None
		
		self.breaking = False
		self.breaking_label = None
		self.breaking_catching = False
		self.breaking_catchlabel = None
		self.breaking_catchexcp = None
		self.breaking_catchregister = None
		
		self.before_error = ""
		self.line_has_error = False
		
		self.catch_errorlevel = 0
		self.catch_errorregister = list()
		
		# Load builtins
		Builtins.BuiltinController().load(self)
		self.debug_exclusions = Builtins.BuiltinController().loadConstants(self)
	
	# The following two functions allow the commanding processes
	# to save bytecode without including the builtin functions
	def unloadBuiltins(self):
		Builtins.BuiltinController().unload(self)
	
	def reloadBuiltins(self):
		Builtins.BuiltinController().load(self)
	
	# This executes the bytecode :)
	def runByteCode(self, code):
		# Code is an array of bytecode instructions
		end = False
		pos = 0
		
		# Loop whileever we are not ending
		while (not end):
			try:
				# Get the current line.
				line = code[pos]
				nojump = False
				oldpos = None
				debug_temp_off = False
				
				# Variables for builtin functions
				self.current_line = pos
				self.current_line_data = code[pos]
				
				# Get the command and arguments for the current line.
				command = line.partition(" ")
				arguments = command[2]
				command = command[0].strip()
				
				# Special: If we are breaking, we should only stop breaking on a BRK command, otherwise,
				#          we should skip this line entirely
				if (self.breaking):
					if (command == "BRK"):
						arguments = arguments.split(",", 0)
						for index, item in enumerate(arguments):
							arguments[index] = item.strip()
						
						if (self.breaking_label == arguments[0] or
							(self.breaking_catching == True and self.breaking_catchlabel == arguments[0])):
							
							if (self.breaking_catching):
								self.register = dict()
								self.register[self.breaking_catchregister] = self.breaking_catchexcp
							
							self.breaking = False
							self.breaking_catching = False
							self.breaking_label = None
							self.breaking_catchlabel = None

							if (self.debug):
								self.debugInterrupt(pos, line)
					elif (self.debug):
						self.debugInterruptBreak(pos, line)
					
					# If we are at the end of the code, make sure we exit
					if (pos == len(code) - 1):
						end = True;
					else:
						# Otherwise increment our position by 1.
						pos += 1;
					
					continue # Next loop
				
				# Now determine what instruction we should do
				if (command == "NEWC" or command == "NEWS" or command == "NEWN" or command == "NEWA"):
					# Create a new temporary variable on the register
					arguments = arguments.split(",", 1)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					if (command == "NEWC"):
						if (arguments[1] in self.classes):
							self.register[arguments[0]] = self.classes[arguments[1]].clone()
						else:
							self.fatalError(pos, line, "Undefined class '" + arguments[1] + "'");
					elif (command == "NEWS"):
						self.register[arguments[0]] = arguments[1][1:-1]
					elif (command == "NEWN"):
						self.register[arguments[0]] = float(arguments[1]);
					elif (command == "NEWA"):
						self.register[arguments[0]] = list();
				
				elif (command == "MOVA" or command == "MOVV" or command == "MOVP"):
					# Move a variable from the register into the variable list
					arguments = arguments.split(",", 2)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					if (command == "MOVV"):
						# Move a value from the register into a variable
						if (arguments[0] in self.register):
							self.variables[arguments[1]] = self.register[arguments[0]]
						else:
							self.fatalError(pos, line, "Undefined register '" + arguments[0] + "'");
					elif (command == "MOVA"):
						# Move a value from the register into an array.
						arrayname = arguments[1]
						arrayindex = int(arguments[2])
						
						if (arguments[0] in self.register):
							if (arrayname in self.variables):
								if (isinstance(self.variables[arrayname], list)):
									if (len(self.variables[arrayname]) > arrayindex):
										self.variables[arrayname][arrayindex] = self.register[arguments[0]]
									elif (len(self.variables[arrayname]) == arrayindex):
										self.variables[arrayname].append(self.register[arguments[0]])
									else:
										self.fatalError(pos, line, "Index " + str(arrayindex) + " is larger than length of '" + arrayname + "'.");
								else:
									self.fatalError(pos, line, "Variable '" + arrayname + "' is not of array type.");
							else:
								self.fatalError(pos, line, "Undefined variable '" + arrayname + "'");
						else:
							self.fatalError(pos, line, "Undefined register '" + arguments[0] + "'");
					elif (command == "MOVP"):
						# Move a value from the register into a property in an object in the register.
						source = arguments[0]
						property = arguments[1]
						object = arguments[2]
						
						if (source in self.register):
							if (object in self.register):
								if (isinstance(self.register[object], Obj)):
									self.register[object].variables[property] = self.register[source]
								else:
									self.fatalError(pos, line, "Variable '" + object + "' is not of Object type.");
							else:
								self.fatalError(pos, line, "Undefined register '" + object + "'");
						else:
							self.fatalError(pos, line, "Undefined register '" + source + "'");
				
				elif (command == "RMOVA" or command == "RMOVV" or command == "RMOVP"):
					# Move a variable from the variable list into the register.
					arguments = arguments.split(",", 2)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					if (command == "RMOVV"):
						# Move a value from the variable into the register
						if (arguments[0] not in self.register):
							if (arguments[1] in self.variables):
								self.register[arguments[0]] = self.variables[arguments[1]]
							else:
								self.fatalError(pos, line, "Undefined variable '" + arguments[1] + "'.");
						else:
							self.fatalError(pos, line, "Register '" + arguments[0] + "' is already defined, therefore, can not copy value to this register.");
					elif (command == "RMOVA"):
						# Move a value from an array into the register.
						arrayname = arguments[1]
						arrayindex = int(arguments[2])
						
						if (arguments[0] not in self.register):
							if (arrayname in self.variables):
								if (isinstance(self.variables[arrayname], list)):
									if (len(self.variables[arrayname]) >= arrayindex):
										self.register[arguments[0]] = self.variables[arrayname][arrayindex]
									else:
										self.fatalError(pos, line, "Index " + str(arrayindex) + " is larger than length of '" + arrayname + "'.");
								else:
									self.fatalError(pos, line, "Variable '" + arrayname + "' is not of array type.");
							else:
								self.fatalError(pos, line, "Undefined variable '" + arrayname + "'");
						else:
							self.fatalError(pos, line, "Register '" + arguments[0] + "' is already defined, therefore, can not copy value to this register.");
					elif (command == "RMOVP"):
						# Move a value from a property in an object to the register.
						source = arguments[0]
						property = arguments[1]
						object = arguments[2]
						
						if (source not in self.register):
							if (object in self.variables):
								if (isinstance(self.variables[object], Obj)):
									if (property in self.variables[object].variables):
										self.register[source] = self.variables[object].variables[property]
									else:
										self.fatalError(pos, line, "Property '" + property + "' does not exist in '" + object + "'.");
								else:
									self.fatalError(pos, line, "Variable '" + object + "' is not of Object type.");
							else:
								self.fatalError(pos, line, "Undefined variable '" + object + "'");
						else:
							self.fatalError(pos, line, "Register '" + arguments[0] + "' is already defined, therefore, can not copy value to this register.");
				
				elif (command == "DMOVV" or command == "DMOVA" or command == "DDMOVA" or command == "DRMOVA" or command == "DDRMOVA" or command == "DRMOVP"):
					# Move a variable from the variable list into the register.
					arguments = arguments.split(",", 2)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					if (command == "DMOVV"):
						# Copies the value of register1 into register2.
						if (arguments[1] not in self.register):
							if (arguments[0] in self.register):
								self.register[arguments[1]] = self.register[arguments[0]]
							else:
								self.fatalError(pos, line, "Undefined register '" + arguments[0] + "'.");
						else:
							self.fatalError(pos, line, "Register '" + arguments[1] + "' is already defined, therefore, can not copy value to this register.");
					elif (command == "DMOVA"):
						# Copies the value of register1 into an array index of register2.
						arrayname = arguments[1]
						arrayindex = int(arguments[2])
						
						if (arguments[0] in self.register):
							if (arrayname in self.register):
								if (isinstance(self.register[arrayname], list)):
									if (len(self.register[arrayname]) > arrayindex):
										self.register[arrayname][arrayindex] = self.register[arguments[0]]
									elif (len(self.register[arrayname]) == arrayindex):
										self.register[arrayname].append(self.register[arguments[0]])
									else:
										self.fatalError(pos, line, "Index " + str(arrayindex) + " is larger than length of '" + arrayname + "'.");
								else:
									self.fatalError(pos, line, "Register '" + arrayname + "' is not of array type.");
							else:
								self.fatalError(pos, line, "Undefined register '" + arrayname + "'");
						else:
							self.fatalError(pos, line, "Undefined register '" + arguments[0] + "'");
					elif (command == "DDMOVA"):
						# Copies the value of register1 into an array index (stored in register3) of register2.
						arrayname = arguments[1]
						if (arguments[2] not in self.register):
							self.fatalError(pos, line, "Undefined register '" + arguments[2] + "'");
						elif (not isinstance(self.register[arguments[2]], float)):
							self.fatalError(pos, line, "Register '" + arguments[2] + "' is not a numeric value and therefore can not be used as an array index.");
						arrayindex = int(self.register[arguments[2]])
						
						if (arguments[0] in self.register):
							if (arrayname in self.register):
								if (isinstance(self.register[arrayname], list)):
									if (len(self.register[arrayname]) > arrayindex):
										self.register[arrayname][arrayindex] = self.register[arguments[0]]
									elif (len(self.register[arrayname]) == arrayindex):
										self.register[arrayname].append(self.register[arguments[0]])
									else:
										self.fatalError(pos, line, "Index " + str(arrayindex) + " is larger than length of '" + arrayname + "'.");
								else:
									self.fatalError(pos, line, "Register '" + arrayname + "' is not of array type.");
							else:
								self.fatalError(pos, line, "Undefined register '" + arrayname + "'");
						else:
							self.fatalError(pos, line, "Undefined register '" + arguments[0] + "'");
					elif (command == "DRMOVA"):
						# Copies the value of the array index in register1 into register2.
						arrayname = arguments[0]
						arrayindex = int(arguments[2])
						
						if (arguments[1] not in self.register):
							if (arrayname in self.register):
								if (isinstance(self.register[arrayname], list)):
									self.register[arguments[1]] = self.register[arrayname][arrayindex]
								else:
									self.fatalError(pos, line, "Register '" + arrayname + "' is not of array type.");
							else:
								self.fatalError(pos, line, "Undefined register '" + arrayname + "'");
						else:
							self.fatalError(pos, line, "Register '" + arguments[1] + "' is already defined, therefore, can not copy value to this register.");
					elif (command == "DDRMOVA"):
						# Copies the value of the array index (stored in register3) in register1 into register2.
						arrayname = arguments[0]
						if (arguments[2] not in self.register):
							self.fatalError(pos, line, "Undefined register '" + arguments[2] + "'");
						elif (not isinstance(self.register[arguments[2]], float)):
							self.fatalError(pos, line, "Register '" + arguments[2] + "' is not a numeric value and therefore can not be used as an array index.");
						arrayindex = int(self.register[arguments[2]])
						
						if (arguments[1] not in self.register):
							if (arrayname in self.register):
								if (isinstance(self.register[arrayname], list)):
									self.register[arguments[1]] = self.register[arrayname][arrayindex]
								else:
									self.fatalError(pos, line, "Register '" + arrayname + "' is not of array type.");
							else:
								self.fatalError(pos, line, "Undefined register '" + arrayname + "'");
						else:
							self.fatalError(pos, line, "Register '" + arguments[1] + "' is already defined, therefore, can not copy value to this register.");
					elif (command == "DRMOVP"):
						# Move a value from a property in an object (stored in a register) to the register.
						object = arguments[0]
						property = arguments[1]
						destination = arguments[2]
						
						if (destination not in self.register):
							if (object in self.register):
								if (isinstance(self.register[object], Obj)):
									if (property in self.register[object].variables):
										self.register[destination] = self.register[object].variables[property]
									else:
										self.fatalError(pos, line, "Property '" + property + "' does not exist in '" + object + "'.");
								else:
									self.fatalError(pos, line, "Register '" + object + "' is not of Object type.");
							else:
								self.fatalError(pos, line, "Undefined register '" + object + "'");
						else:
							self.fatalError(pos, line, "Register '" + destination + "' is already defined, therefore, can not copy value to this register.");
				
				elif (command == "REFA"):
					# Assigns a register the reference to a variable (rather than copying the value)
					arguments = arguments.split(",", 2)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					if (command == "REFA"):
						# Store a reference of an array index in a register.
						register = arguments[0]
						arrayname = arguments[1]
						arrayindex = int(arguments[2])
						
						if (arguments[0] not in self.register):
							if (arrayname in self.variables):
								if (isinstance(self.variables[arrayname], list)):
									if (isinstance(self.variables[arrayname][arrayindex], Obj)):
										self.register[arguments[0]] = self.variables[arrayname][arrayindex];
									else:
										self.fatalError(pos, line, "References can only be made to objects.  Value at ('" + arrayname + "', " + str(arrayindex) + ") is not an Object.");
								else:
									self.fatalError(pos, line, "Variable '" + arrayname + "' is not of array type.");
							else:
								self.fatalError(pos, line, "Undefined variable '" + arrayname + "'");
						else:
							self.fatalError(pos, line, "Register '" + arguments[0] + "' is already defined, therefore, can not store reference in this register.");
				
				elif (command == "CLR"):
					# Clear a register for later use.
					arguments = arguments.split(",", 0)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					if (arguments[0] in self.register):
						del self.register[arguments[0]]
						
				elif (command == "CLRALL"):
					# Clears the entire register
					arguments = arguments.split(",", 0)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					self.register = dict()
						
				elif (command == "CLRV"):
					# Clear a variables for later use.
					arguments = arguments.split(",", 0)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					if (arguments[0] in self.variables):
						del self.variables[arguments[0]]
				
				elif (command == "CMPV" or command == "CMPR"):
					# Compare if two values are equal.
					arguments = arguments.split(",", 2)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					if (command == "CMPV"):
						# Compare a register to a value
						value1 = arguments[1]
						value2 = arguments[2]
						
						if (arguments[0] not in self.register):
							if (value1 in self.register):
								value1 = self.register[value1]
								
								try:
									if (value1 == value2):
										self.register[arguments[0]] = 1;
									elif (value1 == float(value2)):
										self.register[arguments[0]] = 1;
									else:
										self.register[arguments[0]] = 0;
								except:
									self.fatalError(pos, line, "Type of register '" + arguments[1] + "' does not match type of value '" + str(value2) + "'");
							else:
								self.fatalError(pos, line, "Undefined register '" + value1 + "'");
						else:
							self.fatalError(pos, line, "Register '" + arguments[0] + "' is already defined, therefore, can not store result in this register.");
					elif (command == "CMPR"):
						# Compare a register to a register
						self.fatalError(pos, line, "CMPR not implemented.");
				
				elif (command == "BVS" or command == "BVNS"):
					# Break if a variable is / is not set.
					arguments = arguments.split(",", 1)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					if (command == "BVS" and arguments[1] in self.variables):
						self.breaking = True
						self.breaking_label = arguments[0]
					elif (command == "BVNS" and arguments[1] not in self.variables):
						self.breaking = True
						self.breaking_label = arguments[0]
					else:
						self.breaking = False
				
				elif (command == "BRS" or command == "BRNS"):
					# Break if a register is / is not set.
					arguments = arguments.split(",", 1)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					if (command == "BRS" and arguments[1] in self.register):
						self.breaking = True
						self.breaking_label = arguments[0]
					elif (command == "BRNS" and arguments[1] not in self.register):
						self.breaking = True
						self.breaking_label = arguments[0]
					else:
						self.breaking = False
				
				elif (command == "BT" or command == "BF"):
					# Break if a register is / is not true.
					arguments = arguments.split(",", 1)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					if (arguments[1] in self.register):
						if (isinstance(self.register[arguments[1]],float)):
							if (command == "BT" and self.register[arguments[1]] == float(1)):
								self.breaking = True
								self.breaking_label = arguments[0]
							elif (command == "BF" and self.register[arguments[1]] == float(0)):
								self.breaking = True
								self.breaking_label = arguments[0]
							else:
								self.breaking = False
						else:
							self.breaking = False
					else:
						self.fatalError(pos, line, "Undefined register '" + str(value1) + "'");
				
				elif (command == "BU"):
					# Break unconditionally.
					arguments = arguments.split(",", 0)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					self.breaking = True
					self.breaking_label = arguments[0]
				
				elif (command == "BERR"):
					# Break when an error occurs.
					arguments = arguments.split(",", 1)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					self.catch_errorlevel += 1
					self.catch_errorregister.append(arguments[1])
					self.breaking_catchlabel = arguments[0]
				
				elif (command == "ERR"):
					# Raise an error.
					arguments = arguments.split(",", 1)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					self.fatalError(int(arguments[0]), code[pos + int(arguments[0])], arguments[1])
				
				elif (command == "ADD" or command == "MUL" or command == "SUB" or command == "DIV"):
					# Perform a numeric operation
					arguments = arguments.split(",", 1)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					reg = arguments[0]
					value2 = arguments[1]
					
					if (reg in self.register):
						if (isinstance(self.register[reg], float)):
							try:
								# Attempt to convert from number
								real_value = float(value2)
							except ValueError:
								# It's not a number, see if it's another register.
								if (value2 in self.register):
									if (isinstance(self.register[value2], float)):
										real_value = self.register[value2]
									else:
										self.fatalError(pos, line, "'" + value2 + "' is not a numeric register nor a valid numeric value.");
								else:
									# Not a register either, it must be invalid.
									self.fatalError(pos, line, "'" + value2 + "' is not a numeric register nor a valid numeric value.");
							
							if (command == "ADD"):
								try:
									self.register[reg] += real_value
								except ValueError:
									self.fatalError(pos, line, "The addition operation on '" + arguments[0] + "' with value '" + str(value2) + "' could not be completed: unknown arithmetic error.");
							elif (command == "SUB"):
								try:
									self.register[reg] -= real_value
								except:
									self.fatalError(pos, line, "The subtraction operation on '" + arguments[0] + "' with value '" + str(value2) + "' could not be completed: unknown arithmetic error.");
							elif (command == "MUL"):
								try:
									self.register[reg] *= real_value
								except:
									self.fatalError(pos, line, "The multiplication operation on '" + arguments[0] + "' with value '" + str(value2) + "' could not be completed: unknown arithmetic error.");
							elif (command == "DIV"):
								if (real_value == 0):
									# Check for division by 0
									self.fatalError(pos, line, "The division operation on '" + arguments[0] + "' with value '" + str(value2) + "' could not be completed: division by zero.");
								
								try:
									self.register[reg] /= real_value
								except:
									self.fatalError(pos, line, "The division operation on '" + arguments[0] + "' with value '" + str(value2) + "' could not be completed: unknown arithmetic error.");
						elif (isinstance(self.register[reg], str) and command == "ADD"):
							# Check to see if we have quotes around our value2.
							# Quotes indicate literal string (this is the only
							# command where quotes are placed around a string)
							# Without quotes indicates a register.
							
							if (value2.startswith('"') and value2.endswith('"')):
								# Literal string
								real_value = value2[1:-1]
								
							else:
								# From a register
								if (value2 in self.register):
									if (isinstance(self.register[value2], str)):
										real_value = self.register[value2]
									else:
										self.fatalError(pos, line, "Register '" + value2 + "' is not of string type.");
								else:
									# Not a register either, it must be invalid.
									self.fatalError(pos, line, "'" + value2 + "' is not a string register nor a valid literal string value.");
							
							try:
								self.register[reg] += real_value
							except ValueError:
								self.fatalError(pos, line, "The concatenation operation on '" + arguments[0] + "' with value '" + str(value2) + "' could not be completed: unknown concatenation error.");
						else:
							self.fatalError(pos, line, "The register '" + arguments[0] + "' is not a valid type for the requested operation.");
					else:
						self.fatalError(pos, line, "Undefined register '" + reg + "'");
				elif (command == "EQ" or command == "NE" or command == "LT" or command == "LE" or command == "GT" or command == "GE"):
					# Perform an equality test
					arguments = arguments.split(",", 1)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					reg = arguments[0]
					value2 = arguments[1]
					
					if (reg in self.register):
						if (isinstance(self.register[reg], float)):
							try:
								# Attempt to convert from number
								real_value = float(value2)
							except ValueError:
								# It's not a number, see if it's another register.
								if (value2 in self.register):
									if (isinstance(self.register[value2], float)):
										real_value = self.register[value2]
									else:
										self.fatalError(pos, line, "'" + value2 + "' is not of numeric type.");
								else:
									# Not a register either, it must be invalid.
									self.fatalError(pos, line, "'" + value2 + "' is not a numeric register nor a valid numeric value.");
							
							if (command == "EQ"):
								try:
									result = (self.register[reg] == real_value)
								except ValueError:
									self.fatalError(pos, line, "The equality test (equal to) on '" + arguments[0] + "' with value '" + str(value2) + "' could not be completed: unknown comparison error.");
							elif (command == "NE"):
								try:
									result = (self.register[reg] != real_value)
								except ValueError:
									self.fatalError(pos, line, "The equality test (not equal to) on '" + arguments[0] + "' with value '" + str(value2) + "' could not be completed: unknown comparison error.");
							elif (command == "LT"):
								try:
									result = (self.register[reg] < real_value)
								except ValueError:
									self.fatalError(pos, line, "The equality test (less than) on '" + arguments[0] + "' with value '" + str(value2) + "' could not be completed: unknown comparison error.");
							elif (command == "LE"):
								try:
									result = (self.register[reg] <= real_value)
								except ValueError:
									self.fatalError(pos, line, "The equality test (less than or equal to) on '" + arguments[0] + "' with value '" + str(value2) + "' could not be completed: unknown comparison error.");
							elif (command == "GT"):
								try:
									result = (self.register[reg] > real_value)
								except ValueError:
									self.fatalError(pos, line, "The equality test (greater than) on '" + arguments[0] + "' with value '" + str(value2) + "' could not be completed: unknown comparison error.");
							elif (command == "GE"):
								try:
									result = (self.register[reg] >= real_value)
								except ValueError:
									self.fatalError(pos, line, "The equality test (greater than or equal to) on '" + arguments[0] + "' with value '" + str(value2) + "' could not be completed: unknown comparison error.");
							else:
								self.fatalError(pos, line, "Unknown equality test requested.");
							
							if (result):
								self.register[reg] = float(1)
							else:
								self.register[reg] = float(0)
						elif (isinstance(self.register[reg], str)):
							# Check to see if we have quotes around our value2.
							# Quotes indicate literal string (this is the only
							# command where quotes are placed around a string)
							# Without quotes indicates a register.
							
							if (value2.startswith('"') and value2.endswith('"')):
								# Literal string
								real_value = value2[1:-1]
								
							else:
								# From a register
								if (value2 in self.register):
									if (isinstance(self.register[value2], str)):
										real_value = self.register[value2]
									else:
										self.fatalError(pos, line, "Register '" + value2 + "' is not of string type.");
								else:
									# Not a register either, it must be invalid.
									self.fatalError(pos, line, "'" + value2 + "' is not a string register nor a valid literal string value.");
							
							if (command == "EQ"):
								try:
									result = (self.register[reg] == real_value)
								except ValueError:
									self.fatalError(pos, line, "The equality test (equal to) on '" + arguments[0] + "' with value '" + str(value2) + "' could not be completed: unknown comparison error.");
							elif (command == "NE"):
								try:
									result = (self.register[reg] != real_value)
								except ValueError:
									self.fatalError(pos, line, "The equality test (not equal to) on '" + arguments[0] + "' with value '" + str(value2) + "' could not be completed: unknown comparison error.");
							elif (command == "LT"):
								try:
									result = (self.register[reg] < real_value)
								except ValueError:
									self.fatalError(pos, line, "The equality test (less than) on '" + arguments[0] + "' with value '" + str(value2) + "' could not be completed: unknown comparison error.");
							elif (command == "LE"):
								try:
									result = (self.register[reg] <= real_value)
								except ValueError:
									self.fatalError(pos, line, "The equality test (less than or equal to) on '" + arguments[0] + "' with value '" + str(value2) + "' could not be completed: unknown comparison error.");
							elif (command == "GT"):
								try:
									result = (self.register[reg] > real_value)
								except ValueError:
									self.fatalError(pos, line, "The equality test (greater than) on '" + arguments[0] + "' with value '" + str(value2) + "' could not be completed: unknown comparison error.");
							elif (command == "GE"):
								try:
									result = (self.register[reg] >= real_value)
								except ValueError:
									self.fatalError(pos, line, "The equality test (greater than or equal to) on '" + arguments[0] + "' with value '" + str(value2) + "' could not be completed: unknown comparison error.");
							else:
								self.fatalError(pos, line, "Unknown equality test requested.");
							
							if (result):
								self.register[reg] = float(1)
							else:
								self.register[reg] = float(0)
						else:
							self.fatalError(pos, line, "The register '" + arguments[0] + "' is not a valid type for the requested operation.");
					else:
						self.fatalError(pos, line, "Undefined register '" + reg + "'");
				
				elif (command == "CALLF" or command == "CALLC"):
					# Jump into a new section of bytecode (function in global or class scope)
					arguments = arguments.split(",", 3)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					# Get base arguments
					func_name = arguments[0];
					func_resultvar = arguments[2];
					
					# Get the function arguments from a register, if possible
					func_args = list();
					if (arguments[1] in self.register):
						if (isinstance(self.register[arguments[1]], list)):
							func_args = self.register[arguments[1]]
					
					if (command == "CALLF"):
						# Call a global function
						if (func_name in self.functions):
							# Show debug trace if needed
							debug_temp_off = True
							if (self.debug):
								self.debugInterrupt(pos, line)
						
							# Check to see if the number of arguments passed matches the arguments defined
							if (len(func_args) != len(self.functions[func_name].args)):
								self.fatalError(pos, line, "Argument count mismatch while calling '" + func_name + "' (" + str(len(self.functions[func_name].args)) + " defined, " + str(len(func_args)) + " provided)");
						
							# Store the current global variable scope, register and current filename in a temporary variable - we will set it back later.
							global_variables = self.variables
							global_register = self.register
							global_filename = self.filename
							self.variables = dict()
							self.register = dict()
							self.filename = "<function " + func_name + ">"
							Builtins.BuiltinController().loadConstants(self)
							
							# Call the function
							self.functions[func_name].execute(self, func_args);
							
							# Set the variable scope and registers back again.
							self.variables = global_variables
							self.register = global_register
							self.filename = global_filename
							
							# Store the result if possible.
							if (self.return_scope != None):
								self.register[func_resultvar] = self.return_scope
							self.return_scope = None
						else:
							self.fatalError(pos, line, "Undefined function '" + func_name + "'");
					elif (command == "CALLC"):
						# Call a function in a class
						class_obj = arguments[3]
						if (class_obj in self.register):
							if (isinstance(self.register[class_obj], Obj)):
								if (func_name in self.register[class_obj].functions):
									# Show debug trace if needed
									debug_temp_off = True
									if (self.debug):
										self.debugInterrupt(pos, line)
									
									# We need to load a reference to the object
									# at the start of the function arguments.
									func_args.insert(0, self.register[class_obj]);
								
									# Check to see if the number of arguments passed matches the arguments defined
									if (len(func_args) != len(self.register[class_obj].functions[func_name].args)):
										self.fatalError(pos, line, "Argument count mismatch while calling '" + func_name + "' defined in '" + self.register[class_obj].type + "' (" + str(len(self.register[class_obj].functions[func_name].args)) + " defined, " + str(len(func_args)) + " provided)");
								
									# Store a reference to the object it the register
									# because we are about to clear the register...
									obj_ref = self.register[class_obj]
								
									# Store the current global variable scope and register in a temporary variable - we will set it back later.
									global_variables = self.variables
									global_register = self.register
									global_filename = self.filename
									self.variables = dict()
									self.register = dict()
									self.filename = "<function " + func_name + " in " + obj_ref.type + ">"
									Builtins.BuiltinController().loadConstants(self)
									
									# Call the function
									obj_ref.functions[func_name].execute(self, func_args);
									
									# Set the variable scope and registers back again.
									self.variables = global_variables
									self.register = global_register
									self.filename = global_filename
									
									# Store the result if possible.
									if (self.return_scope != None):
										self.register[func_resultvar] = self.return_scope
									self.return_scope = None
								else:
									self.fatalError(pos, line, "Undefined function '" + func_name + "' in class object '" + self.register[class_obj].type + "'");
							else:
								self.fatalError(pos, line, "Register '" + class_obj + "' is not of Object type.");
						else:
							self.fatalError(pos, line, "Undefined register '" + class_obj + "'");
				
				elif (command == "RET"):
					# Return a variable.
					arguments = arguments.split(",", 0)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					reg = arguments[0]
					
					if (reg in self.register):
						self.return_scope = self.register[reg]
					else:
						self.fatalError(pos, line, "Undefined register '" + reg + "'");
				
				elif (command == "LBL"):
					# Set a label.
					arguments = arguments.split(",", 0)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					self.bytecode_labels[arguments[0]] = pos
				
				elif (command == "JMPR" or command == "JMPA" or command == "JMPL"):
					# Jump relatively or absolutely.
					arguments = arguments.split(",", 0)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					try:
						nline = int(arguments[0])
						oldpos = pos
						if (command == "JMPR"):
							pos += nline
						elif (command == "JMPA"):
							pos = nline
						else:
							self.fatalError(pos, line, "Unknown jump command.");
					except:
						if (command == "JMPL"):
							if (arguments[0] in self.bytecode_labels):
								pos = self.bytecode_labels[arguments[0]]
							else:
								self.fatalError(pos, line, "Attempted jump to undefined label.");
						else:
							self.fatalError(pos, line, "Unknown jump command.");
					nojump = True # tell the executor not to increment the line at the end of this command
					
				elif (command.startswith("#") or command == ""):
					# Comment or blank line, skip this line
					pass
					
				elif (command.startswith(";")):
					# Interpreter information, skip this line
					arguments = code[pos][1:].split(":", 2)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					self.line_has_error = False
					self.current_interpreted_line_filename = arguments[0]
					self.current_interpreted_line_number = arguments[1]
					self.current_interpreted_line_string = arguments[2].strip()
				
				elif (command == "BRK"):
					# Break command was encountered but we are not in a breaking loop.
					# We must check if this break is part of a try-catch.
					arguments = arguments.split(",", 0)
					for index, item in enumerate(arguments):
						arguments[index] = item.strip()
					
					if (len(self.catch_errorregister) > 0):
						if (self.catch_errorregister[len(self.catch_errorregister) - 1] == arguments[0]):
							self.catch_errorregister.pop()
							self.catch_errorlevel -= 1;
					
					pass
				
				else:
					self.fatalError(pos, line, "Undefined instruction '" + command + "' with arguments '" + arguments.strip() + "'");
				
				# If we are in debugging mode, show the state
				if (self.debug and not debug_temp_off and line.strip() != ""):
					# Detect if we jumped lines
					if (oldpos == None):
						self.debugInterrupt(pos, line)
					else:
						self.debugInterrupt(oldpos, line)
			
			#except BaseException, err:
			#	self.fatalErrorN(pos, line, """An internal Python error occurred.
#  """ + str(type(err).__name__) + """: """ + str(err));
			finally:
				pass
			
			# If we are at the end of the code, make sure we exit
			if (pos == len(code) - 1):
				end = True;
			elif (nojump == False):
				# Otherwise increment our position by 1.
				pos += 1;
	
	def debugByteCode(self, code):
		self.debug = True
		self.runByteCode(code)
		self.debug = False
	
	def debugInterrupt(self, lineno, linecode):
		print """==========================================================
Debug Interrupt:
  File """ + '"' + self.filename + '"' + """, line """ + str(lineno) + """
    """ + linecode + """

has just been executed.  The executor's current state is:

--- Variables ---"""

		t = dict(self.variables)
		for i in self.debug_exclusions:
			if (i in t):
				del t[i]
		
		if (len(t) == 0):
			print "Empty";
		else:
			self.debugDict(t, 0);
		
		print """--- Register ---"""
		
		if (len(self.register) == 0):
			print "Empty";
		else:
			self.debugDict(self.register, 0);
		
		print """--- Result Container ---"""
		if (self.return_scope == None):
			print "Empty";
		else:
			print str(self.return_scope)
		
		print """
Press enter to continue when ready.
=========================================================="""
		raw_input("")
	
	def debugInterruptBreak(self, lineno, linecode):
		print """==========================================================
Debug Interrupt:
  File """ + '"' + self.filename + '"' + """, line """ + str(lineno) + """
    """ + linecode + """

has just been skipped.

Press enter to continue when ready.
=========================================================="""
		raw_input("")
	
	def debugList(self, array, indent):
		for index, item in enumerate(array):
			# see if we should output value
			s = ""
			if (isinstance(array[index], str) or isinstance(array[index], int) or isinstance(array[index], float)):
				s = " = " + str(array[index]);
			
			if (isinstance(array[index], Obj)):
				a = str(array[index].type);
				if (a == "NoneType"): a = "nothing"
				print "".ljust(indent, " ") + str(index) + ": (" + a + ")" + s
			elif (isinstance(array[index], Func)):
				print "".ljust(indent, " ") + str(index) + ": (function)" + s
			else:
				a = type(array[index]).__name__;
				if (a == "NoneType"): a = "nothing"
				print "".ljust(indent, " ") + str(index) + ": (" + a + ")" + s
			if (isinstance(array[index], list)):
				self.debugList(array[index], indent + 2);
			elif (isinstance(array[index], dict)):
				self.debugDict(array[index], indent + 2);
			elif (isinstance(array[index], Obj)):
				self.debugObject(array[index], indent + 2);
			elif (isinstance(array[index], Func)):
				self.debugFunction(array[index], indent + 2);
	
	def debugDict(self, array, indent):
		for index, item in enumerate(array):
			# see if we should output value
			s = ""
			if (isinstance(array[item], str) or isinstance(array[item], int) or isinstance(array[item], float)):
				s = " = " + str(array[item]);
		
			if (isinstance(array[item], Obj)):
				a = str(array[item].type);
				if (a == "NoneType"): a = "nothing"
				print "".ljust(indent, " ") + str(index) + ": " + str(item) + " (" + a + ")" + s
			elif (isinstance(array[item], Func)):
				print "".ljust(indent, " ") + str(index) + ": " + str(item) + " (function)" + s
			else:
				a = type(array[item]).__name__;
				if (a == "NoneType"): a = "nothing"
				print "".ljust(indent, " ") + str(index) + ": " + str(item) + " (" + a + ")" + s
			if (isinstance(array[item], list)):
				self.debugList(array[item], indent + 2);
			elif (isinstance(array[item], dict)):
				self.debugDict(array[item], indent + 2);
			elif (isinstance(array[item], Obj)):
				self.debugObject(array[item], indent + 2);
			elif (isinstance(array[item], Func)):
				self.debugFunction(array[item], indent + 2);
	
	def debugObject(self, obj, indent):
		indent += 2
		print "".ljust(indent - 2, " ") + "Variables:"
		if (len(obj.variables) == 0):
			print "".ljust(indent, " ") + "Empty";
		else:
			for index, item in enumerate(obj.variables):
				# see if we should output value
				s = ""
				if (isinstance(obj.variables[item], str) or isinstance(obj.variables[item], int) or isinstance(obj.variables[item], float)):
					s = " = " + str(obj.variables[item]);
			
				if (isinstance(obj.variables[item], Obj)):
					a = str(obj.variables[item].type);
					if (a == "NoneType"): a = "nothing"
					print "".ljust(indent, " ") + str(index) + ": " + str(item) + " (" + a + ")" + s
				elif (isinstance(obj.variables[item], Func)):
					print "".ljust(indent, " ") + str(index) + ": " + str(item) + " (function)" + s
				else:
					a = type(obj.variables[item]).__name__;
					if (a == "NoneType"): a = "nothing"
					print "".ljust(indent, " ") + str(index) + ": " + str(item) + " (" + a + ")" + s
				if (isinstance(obj.variables[item], list)):
					self.debugList(obj.variables[item], indent + 2);
				elif (isinstance(obj.variables[item], dict)):
					self.debugDict(obj.variables[item], indent + 2);
				elif (isinstance(obj.variables[item], Obj)):
					self.debugObject(obj.variables[item], indent + 2);
				elif (isinstance(obj.variables[item], Func)):
					self.debugFunction(obj.variables[item], indent + 2);
		
		print "".ljust(indent - 2, " ") + "Functions:"
		if (len(obj.functions) == 0):
			print "".ljust(indent, " ") + "Empty";
		else:
			self.debugDict(obj.functions, indent);
		
		if (obj.constructor != None):
			print "".ljust(indent - 2, " ") + "Constructor:"
			self.debugFunction(obj.constructor, indent);
	
	def debugFunction(self, function, indent):
		c = function.code.split("\n")
		print "".ljust(indent, " ") + "Arguments:"
		if (len(function.args) == 0):
			print "".ljust(indent + 2, " ") + "None";
		else:
			for i in function.args:
				print "".ljust(indent + 2, " ") + i
		if (self.debug == False):
			print "".ljust(indent, " ") + "Bytecode:"
			if (len(c) == 0):
				print "".ljust(indent + 2, " ") + "Empty";
			else:
				for i in c:
					print "".ljust(indent + 2, " ") + i
	
	def finalState(self, needsbreak = True):
		# Unload builtins
		Builtins.BuiltinController().unload(self)
		
		#oldstdout = sys.stdout
		#f = open("finalstate.txt","w")
		#sys.stdout = f
		
		if (needsbreak):
			print """=========================================================="""
		print """
The final state of the bytecode executor is:

--- Variables ---"""

		if (len(self.variables) == 0):
			print "Empty";
		else:
			self.debugDict(self.variables, 0);
		
		print """--- Register ---"""
		
		if (len(self.register) == 0):
			print "Empty";
		else:
			self.debugDict(self.register, 0);
		
		print """--- Functions ---"""
		
		if (len(self.functions) == 0):
			print "Empty";
		else:
			self.debugDict(self.functions, 0);
		
		print """--- Classes ---"""
		
		if (len(self.classes) == 0):
			print "Empty";
		else:
			self.debugDict(self.classes, 0);
		
		print """
=========================================================="""
		
		#sys.stdout = oldstdout
		#f.close()
	
		# Reload builtins
		Builtins.BuiltinController().load(self)
	
	def fatalError(self, lineno, code_text, error_text):
		# We only want to display one error per line.
		#if (self.line_has_error):
		#	return
		
		self.line_has_error = True
	
		# We may want to catch the error.
		if (self.catch_errorlevel > 0):
			self.breaking_catchregister = self.catch_errorregister.pop()
			self.catch_errorlevel -= 1;
			self.breaking = True
			self.breaking_catching = True
			self.breaking_catchexcp = ExceptionBIC.ExceptionBIC("exception")
			
			if (self.current_interpreted_line_string != None):
				self.breaking_catchexcp.variables["text"] = error_text
				self.breaking_catchexcp.variables["file"] = self.current_interpreted_line_filename
				self.breaking_catchexcp.variables["line"] = int(self.current_interpreted_line_number)
				self.breaking_catchexcp.variables["code"] = self.current_interpreted_line_string
			else:
				self.breaking_catchexcp.variables["text"] = error_text
				self.breaking_catchexcp.variables["file"] = self.filename
				self.breaking_catchexcp.variables["line"] = lineno
				self.breaking_catchexcp.variables["code"] = None
		else:
			interpreter_info = ""
			if (self.current_interpreted_line_string != None):
				interpreter_info = """File """ + '"' + self.current_interpreted_line_filename + '"' + """, line """ + self.current_interpreted_line_number + """
    """ + self.current_interpreted_line_string + """
  """
			print self.before_error + """Traceback (most recent call last):
  """ + interpreter_info + """File """ + '"' + self.filename + '"' + """ (bytecode), line """ + str(lineno) + """
    """ + code_text + """

RuntimeError: """ + error_text + """
"""
			sys.exit()
	
	def fatalErrorN(self, lineno, code_text, error_text):
		interpreter_info = ""
		if (self.current_interpreted_line_string != None):
			interpreter_info = """File """ + '"' + self.current_interpreted_line_filename + '"' + """, line """ + self.current_interpreted_line_number + """
    """ + self.current_interpreted_line_string + """
  """
		print self.before_error + """Traceback (most recent call last):
  """ + interpreter_info + """File """ + '"' + self.filename + '"' + """ (bytecode), line """ + str(lineno) + """
    """ + code_text + """

RuntimeError: """ + error_text + """
"""
		sys.exit()